﻿/*
 * Copyright 2010 Pieter De Rycke
 *
 * This file is part of Frozen Bubble XNA.
 *
 * Frozen Bubble XNA is free software: you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2, as published by the Free Software Foundation.
 *
 * Frozen Bubble XNA is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public
 * License along with Frozen Bubble XNA. If not, see 
 * <http://www.gnu.org/licenses/>.
 *
 * Artwork:
 *    Alexis Younes <73lab at free.fr>
 *      (everything but the bubbles)
 *    Amaury Amblard-Ladurantie <amaury at linuxfr.org>
 *      (the bubbles)
 *
 * Soundtrack:
 *    Matthias Le Bidan <matthias.le_bidan at caramail.com>
 *      (the three musics and all the sound effects)
 *
 * Design & Programming:
 *    Guillaume Cottenceau <guillaume.cottenceau at free.fr>
 *      (design and manage the project, whole Perl sourcecode)
 *
 * XNA and Windows Phone 7 port:
 *    Pieter De Rycke
 *
 * Websites:
 *    http://www.frozen-bubble.org/
 *    http://pieterderycke.wordpress.com/
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Collections;

namespace FrozenBubble
{
    public class HighScoreManager : IEnumerable<HighScore>
    {
        private const int MaxHighScores = 10;

        public IList<HighScore> _scores;

        public HighScoreManager()
        {
            _scores = new List<HighScore>();
        }

        public HighScoreManager(XElement highscoresElement)
        {
            _scores = new List<HighScore>();
            Read(highscoresElement);
        }

        public bool IsHighScore(int level, int time)
        {
            if (_scores.Count < MaxHighScores)
                return true;
            else
            {
                return _scores.Any((s) => s.Level < level || (s.Level == level && s.TotalPlayTime > time));
            }
        }

        public void AddHighScore(string player, int level, int time, bool hasWon)
        {
            int pos = GetScorePosition(level, time);

            if (pos < MaxHighScores)
            {
                player = player.ToUpperInvariant();
                _scores.Insert(pos, new HighScore(player, level, time, hasWon));
                if (_scores.Count > MaxHighScores)
                    _scores.RemoveAt(_scores.Count - 1);
            }
        }

        public XElement Serialize()
        {
            XElement highscoreElement = new XElement("highscores");

            foreach (HighScore score in _scores)
            {
                XElement scoreElement = new XElement("score");
                scoreElement.Add(new XElement("player", score.PlayerName));
                scoreElement.Add(new XElement("level", score.Level));
                scoreElement.Add(new XElement("time", score.TotalPlayTime));
                scoreElement.Add(new XElement("won", score.HasWon));
                highscoreElement.Add(scoreElement);
            }

            return highscoreElement;
        }

        private void Read(XElement highscoresElement)
        {
            var query = from s in highscoresElement.Elements("score")
                        orderby int.Parse(s.Element("level").Value) descending,
                        long.Parse(s.Element("time").Value) ascending
                        select s;

            foreach (XElement score in query)
            {
                string playerName = score.Element("player").Value;
                int level = int.Parse(score.Element("level").Value);
                int time = int.Parse(score.Element("time").Value);
                bool hasWon = bool.Parse(score.Element("won").Value);

                _scores.Add(new HighScore(playerName, level, time, hasWon));
            }
        }

        private int GetScorePosition(int level, long time)
        {
            // This is not efficient code, but it is only a very small list (10 elements)
            if (_scores.Any((s) => s.Level < level || (s.Level == level && s.TotalPlayTime > time)))
            {
                HighScore score = _scores.First((s) => s.Level < level || (s.Level == level && s.TotalPlayTime > time));
                return _scores.IndexOf(score);
            }
            else
                return _scores.Count; 
        }

        #region IEnumerable<HighScore> Members

        public IEnumerator<HighScore> GetEnumerator()
        {
            return _scores.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        IEnumerator IEnumerable.GetEnumerator()
        {
            return _scores.GetEnumerator();
        }

        #endregion
    }
}
